#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Copyright © 启明星辰 版权所有
# @Time    : 2023/11/9 10:24
# @Author  : 胡浩浩
# @File    : case_api_count.py
# @IDE     : PyCharm
# @description : 测试用例接口统计
import json
import os
import time

import jmespath
import requests
import yaml
from pyecharts.charts import Pie
from pywebio import session
from pywebio.output import *
from pywebio.pin import put_select, put_file_upload, pin
from pywebio.session import eval_js
from pyecharts import options as opts

from apps.commons.comms import IPADDRESS
from apps.commons.json_tools import read_json_file
from apps.src.menus import show_menus
from config import APIPORT

api_data_path = "data/"

api_dict = {}
error_dict = {}
total_api = {}
product_name = ""
# model_dict = read_json_file("data/model_config.json")

group_api_list_all = []


def show_api_list(data_dict: dict, show_no_cover_all_api_dict, all_dict, error_file_dict):
    print(f"{time.strftime('%Y-%m-%d %H:%M:%S：')}我正在调试中")
    print(data_dict)
    show_data = []
    key_list=[]
    if data_dict:
        data_list = []
        for key, value in data_dict.items():
            number = 0
            if value:
                key_list.append(key)
                if all_dict and all_dict.get(key):
                    number += 1
                    data_list.append([put_collapse(f"{key}({len(value)})", put_text('\n'.join(value)))])
            data_list.insert(0, [
                put_html(f'<h4 style="width:600px">模块分组({number})</h4>')
            ])
            data = {
                "title": f"{key}已覆盖",
                "content": [
                    put_table(
                        data_list
                    )
                ]
            }
            show_data.append(data)
    print(key_list)
    if show_no_cover_all_api_dict:
        for key, value in show_no_cover_all_api_dict.items():
            number = 0
            data_list = []
            for k in key_list:
                if all_dict.get(k):
                    number += 1
                    data_list.append([put_collapse(f"{k}({len(value)})", put_text('\n'.join(value)))])
            data_list.insert(0, [
                put_html(f'<h4 style="width:600px">模块分组({number})</h4>')
            ])
            data = {
                "title": f"{key}未覆盖",
                "content": [
                    put_table(
                        data_list
                    )
                ]
            }
            show_data.append(data)
    if data_dict:
        for key, value in data_dict.items():
            number = 0
            data_list = []
            for k in key_list:
                if not all_dict.get(k):
                    number += 1
                    data_list.append([put_collapse(f"{k}({len(value)})", put_text('\n'.join(value)))])
            data_list.insert(0, [
                put_html(f'<h4 style="width:600px">模块分组({number})</h4>')
            ])
            data = {
                "title": f"非{key}接口统计",
                "content": [
                    put_table(
                        data_list
                    )
                ]
            }
            show_data.append(data)
    if error_file_dict:
        number = len(error_file_dict)
        data_list = []
        for key, value in error_file_dict.items():
            data_list.append(put_collapse(f"{key}", put_text(value)))

        data = {
            "title": f"错误文件列表({number})",
            "content": data_list
        }
        show_data.insert(0, data)

    return put_scrollable(put_tabs(show_data), 500)


def show_total_number(user_id):
    # result_list = read_json_file("data/count_data.json")
    result_list = requests.get(f"http://{IPADDRESS}:{APIPORT}/count_data").json()

    # print(json.dumps(model_dict_list,ensure_ascii=False))
    case_api_dict = {}
    all_api_dict = {}
    no_cover_all_api_dict = {}
    error_file_dict = {}
    product_local = pin.product_local
    # print(f"{time.strftime('%Y-%m-%d %H:%M:%S：')}product_local--------------", product_local)
    product_name = product_local.split(':')[0]
    product_name_version = product_local[len(product_local.split(':')[0])+1:]
    model_dict = json.loads(
        requests.get(f"http://{IPADDRESS}:{APIPORT}/group_info?product_name={product_name_version}").json()[
            "group_info"])
    # print("模块分组",model_dict)
    # 通过产品标识获取对应产品的全部接口集合和对应的数量

    all_api_paths = []
    # [[cd.product_name, cd.product_version, cd.cover_rate, cd.all_api_list, cd.case_api_list] for cd in count_data]
    result_list = jmespath.search(f"@[?@[1]==`{product_name_version}`]|[0]",result_list)
    # print("模块分组",result_list)
    all_api_paths=result_list[3]
    all_api_dict={}
    all_api_dict[product_name_version]={"未分组接口":[]}
    no_cover_all_api_dict = {}
    no_cover_all_api_dict[product_name_version] = {"未分组接口": []}
    case_api_dict = {}
    case_api_dict[product_name_version] = {"未分组接口": []}
    for key in model_dict.keys():
        all_api_dict[product_name_version][key] = []
        no_cover_all_api_dict[product_name_version][key] = []
        case_api_dict[product_name_version][key] = []


    account_case_api_list = []
    yaml_file_list = pin.yml_files_local
    num = 0
    if not yaml_file_list:
        toast("请先上传yml测试用例,再进行统计", color="red")
        return
    with use_scope("data_list"):
        put_text("正在统计中,请稍后......")
        put_processbar('bar')
    for f in yaml_file_list:
        num += 1
        set_processbar('bar', num / len(yaml_file_list))
        try:
            yaml_data = yaml.safe_load(f['content'])
            # print(f"{time.strftime('%Y-%m-%d %H:%M:%S：')}", f["filename"])
            if (".yml" not in f["filename"]) and (".yaml" not in f["filename"]):
                error_dict[user_id][f["filename"]] = "用例文件类型不正确"
                continue
            if not yaml_data:
                if not error_dict[user_id].get(f["filename"]):
                    error_dict[user_id][f["filename"]] = "用例文件不能为空"
            else:
                suit_name = yaml_data.get("suite_name") if yaml_data.get("suite_name") else yaml_data.get(
                    "scenario_name")
                suit_desc = yaml_data.get("suite_desc") if yaml_data.get("suite_desc") else yaml_data.get(
                    "scenario_desc")

                if not suit_name or not suit_desc or not yaml_data.get("test_steps"):
                    if not error_dict[user_id].get(f["filename"]):
                        error_dict[user_id][f["filename"]] = "用例格式不正确"
                else:
                    case_path_result0 = jmespath.search("test_steps[].req_info.address", yaml_data)
                    case_path_result1 = jmespath.search("test_steps[].req_info.path", yaml_data)
                    case_path_result = case_path_result0 + case_path_result1
                    for path in case_path_result:
                        # 将测试用例中address中的${product}去除，保持格式和swagger中的接口格式一致
                        path = path.replace("/${product}", "")
                        # print(path)
                        if path not in all_api_paths:
                            # print(path)
                            all_api_paths.append(path)
                        else:
                            # 判断中path中是否包含变量引用，如果存在引用，则需要找出swagger中也包含引用的接口去做比较
                            if "${" in path:
                                for a_path in all_api_paths:
                                    if "{" in a_path:
                                        # 测试用例中使用的${}进行变量引用，swagger中使用的是{}进行的变量引用
                                        # 在这里判断测试用例${左侧的内容与swagger中{左侧的内容相等且测试用例}右侧的内容与swagger中}右侧的内容相等，则测试用例中的path是在swagger全集中的
                                        if path.split("${")[0] == a_path.split("{")[0] and path.split("}")[1] == \
                                                a_path.split("}")[1]:
                                            if a_path not in account_case_api_list:
                                                account_case_api_list.append(a_path)
                            else:
                                account_case_api_list.append(path)
        except Exception as e:

            error_file_dict[f['filename']] = e.__str__()




    for path in all_api_paths:
        flag = False
        for model_key, model_value in model_dict.items():
            for v in model_value:
                if not flag and path.startswith(v):
                    all_api_dict[product_name_version][model_key].append(path)
                    flag = True
                    break
        if not flag:
            all_api_dict[product_name_version]["未分组接口"].append(path)


    if all_api_paths and account_case_api_list:
        difference = list(set(all_api_paths) - set(account_case_api_list))
        difference.sort()
    else:
        difference = []
    for path in difference:
        flag = False
        for model_key, model_value in model_dict.items():
            for v in model_value:
                if not flag and path.startswith(v):
                    no_cover_all_api_dict[product_name_version][model_key].append(path)
                    flag = True
                    break

    account_case_api_list = set(account_case_api_list)
    for path in account_case_api_list:
        flag = False
        for model_key, model_value in model_dict.items():
            for v in model_value:
                if not flag and path.startswith(v):
                    # print("我在")
                    case_api_dict[product_name_version][model_key].append(path)
                    flag = True
                    break
        if not flag:
            case_api_dict["未分组接口"].append(path)
    all_api_paths.sort()
    for path in all_api_paths:
        flag = False
        for model_key, model_value in model_dict.items():
            for v in model_value:
                if not flag and path.startswith(v):
                    # print("我在")
                    all_api_dict[product_name_version][model_key].append(path)
                    flag = True
                    break
        if not flag:
            all_api_dict[product_name_version]["未分组接口"].append(path)

    # print(all_api_dict)
    # print(case_api_dict)
    # print(no_cover_all_api_dict)
    def show_case_api_model():

        print(f"{time.strftime('%Y-%m-%d %H:%M:%S：')}", product_name_version)
        show_data = {}
        for item in case_api_dict[product_name_version]:
            show_data[item] = {}
        for key, value in case_api_dict[product_name_version].items():
            # print(case_api_dict)
            # print(f"{time.strftime('%Y-%m-%d %H:%M:%S：')}", key)
            # print(f"{time.strftime('%Y-%m-%d %H:%M:%S：')}", value)
            # print(case_api_dict[product_name_version][key])
            # print(all_api_dict[product_name_version][key])
            if value:
                # print(f"{time.strftime('%Y-%m-%d %H:%M:%S：')}我执行了。。。。。。。。。。。。。。。")
                show_data[key] = round(
                    len(set(case_api_dict[product_name_version][key])) / len(
                        set(all_api_dict[product_name_version][key])) * 100, 2)

        c = (
            Pie()
            .add(
                f"{product_name}",
                [
                    list(z)
                    for z in zip(
                    show_data.keys(),
                    show_data.values(),
                )
                ],
                radius=[0, 100],
                center=["35%", "60%"],
            )
            .set_global_opts(
                title_opts=opts.TitleOpts(title="yml接口统计"),
                legend_opts=opts.LegendOpts(type_="scroll", pos_left="80%", orient="vertical", item_height=10,
                                            item_width=15),
            )
            .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}%"))

        )
        c.width = "100%"
        c.height = "500px"
        return put_html(c.render_notebook(), scope="data_list")

    with use_scope("data_list", clear=True):

        put_row([
            None,
            put_button("重新统计", lambda: eval_js('window.location.reload();'), small=True),

        ], size="70%")
        put_row([
            show_case_api_model(),
            show_api_list(case_api_dict[product_name_version], no_cover_all_api_dict[product_name_version],
                          all_api_dict.get(product_name_version) if all_api_dict else {}, error_file_dict)
        ], size="50%", scope="data_list")


def business_data_list():
    product_info = requests.get(f"http://{IPADDRESS}:{APIPORT}/product_info")
    # print(product_info.json())
    product_info_list = [item[0] for item in product_info.json()]
    return product_info_list


def html_show_api_count():
    """
    接口统计

    :return:
    """
    show_menus()
    product_list = business_data_list()
    user_id = session.info.user_ip.replace(".", "")
    # print(f"{time.strftime('%Y-%m-%d %H:%M:%S：')}", user_id)
    if not api_dict.get(user_id):
        api_dict[user_id] = {}
        error_dict[user_id] = {}
    put_tabs([
        {
            "title": "yml统计汇总",
            "content": [
                put_html("<hr>"),
                put_html("<h3>执行信息</h3>"),
                put_row([
                    None,
                    put_text("产品标识"),
                    put_select("product_local", product_list, help_text="请选择产品标识"),
                    None
                ], size="10% 10% 50%"),
                put_html("<br>"),
                put_row([
                    None,
                    put_text("选择yml用例"),
                    put_file_upload("yml_files_local", accept=['.yaml', '.yml'], placeholder="请上传本地的yml用例文件",
                                    multiple=True),
                    None,

                    None
                ], size="10% 10% 50% 5%"),
                put_html("<br>"),
                put_row([
                    None,
                    None,
                    None,
                    put_button("执行", onclick=lambda: show_total_number(user_id), small=True),
                ], size="10% 10% 55% 5%"
                )]
        }
    ], scope="data_list")
